package cz.pecinovsky.česky.oopnz._134_;
//Příliš žluťoučký kůň úpěl ďábelské ódy

//import cz.pecinovsky.česky.oopnz.správce.IPosuvný;
import cz.pecinovsky.česky.oopnz.správce.Kreslítko;
import cz.pecinovsky.česky.oopnz.správce.Obdélník;
import cz.pecinovsky.česky.oopnz.správce.SprávcePlátna;


//import static cz.pecinovsky.česky.oopnz._134_.IModulový_134_    .IModulový;
import static cz.pecinovsky.česky.oopnz._134_.IOtočný_136_      .IOtočný;
import static cz.pecinovsky.česky.oopnz._134_.StavSemaforu_142_ .StavSemaforu;
import static cz.pecinovsky.česky.oopnz._134_.StavSemaforu_142_ .StavSemaforu.*;
import static cz.pecinovsky.česky.oopnz._134_.Světlo_134_       .Světlo;


//import static cz.pecinovsky.česky.oopnz._134_.Semafor_134_      .Semafor;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ Konec ignorovaného počátečního textu +++++
//%I+ >=132z
//
//import cz.pecinovsky.česky.oopnz.správceplátna.IPosuvný;
//import cz.pecinovsky.česky.oopnz.správceplátna.Kreslítko;
//import cz.pecinovsky.česky.oopnz.správceplátna.Obdélník;
//import cz.pecinovsky.česky.oopnz.správceplátna.SprávcePlátna;
//%I-

import cz.pecinovsky.česky.oopnz.utility.Barva;
import cz.pecinovsky.česky.oopnz.utility.IO;
//%A+ >136
import cz.pecinovsky.česky.oopnz.utility.Oblast;
//%A-
import cz.pecinovsky.česky.oopnz.utility.Pozice;
//%A+ >136
import cz.pecinovsky.česky.oopnz.utility.Směr8;
//%A-
//%I+ >142
//
//
//import static cz.pecinovsky.česky.oopnz.město.StavSemaforu.*;
//%I-
//%X+ xxxxx Začátek přeskakovaného textu xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   oopnz._115_._116_Semafor_119
 * Následující: Prozatím není
 *
 * Projekt  020z - Komentáře
 *   + Začlenění do standardní šablony + Komentáře
 *
 * Projekt  021z - Použití this
 *   ~ V prvních dvou konstruktorech nahrazena původní těla
 *     příkazem this volajícím obecnější konstruktor
 *
 * Projekt  022z - Přetěžování
 *   + Přidány další dva konstruktory
 *   ~ Ve třetím konstruktoru nahrazeno tělo příkazem this
 *     volající přidaný obecnější konstruktor
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */
public class Semafor_134_
{    private Semafor_134_() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- Konec přeskakovaného textu -----


/*******************************************************************************
 * Instance třídy {@code Semafor} představují semafory obdobné těm,
 * které řídí dopravu na křižovatkách.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
//%I+ <136
//public class Semafor implements IModulový
//%I-
//%A+ >136
public class Semafor implements IOtočný
//%A-
     {
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    private static final int IMPLICITNÍ_X = 0;

    private static final int IMPLICITNÍ_Y = 0;

    private static final int IMPLICITNÍ_MODUL = 50;

    private static final Barva IMPLICITNÍ_BARVA_KRABICE = Barva.ČERNÁ;
//%A+ >136

    private static final Směr8 IMPLICITNÍ_SMĚR = Směr8.VÝCHOD;

    /** Plátno, na které se bude instance kreslit. */
    private static final SprávcePlátna SP = SprávcePlátna.getInstance();
//%A-



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

     /** Počet doposud vytvořených instancí. */
     private static int počet = 0;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Pořadové (identifikační) číslo dané instance. */
    private final int ID;

    /** Krabice, v níž jsou umístěna světla. */
    private final Obdélník krabice;

    /** Horní, červené světlo. */
    private final Světlo červená;

    /** Střední, žluté (oranžové) světlo. */
    private final Světlo žlutá;

    /** Dolní, zelené světlo. */
    private final Světlo zelená;



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    /** Název instance sestávající implicitně z názvu třídy a ID instance */
    private String název;
//%A+ >136

    /** Bodová x-ová souřadnice instance. */
    private int xPos;

    /** Bodová y-ová souřadnice instance. */
    private int yPos;

    /** Velikost strany čverce vyplněného šipkou v bodech. */
    private int modul;

    /** Směr, do nějž je šipka natočena. */
    private Směr8 směr;
//%A-
//%A+ >142

    /** Stav, v němž se semafor právě nachází. */
    private StavSemaforu stav;
//%A-



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří semafor implicitních rozměrů a barvy
     * umístěný v levém horním rohu plátna.
     */
    public Semafor()
    {
        this(IMPLICITNÍ_X, IMPLICITNÍ_Y);
    }


    /***************************************************************************
     * Vytvoří semafor implicitních rozměrů a barvy
     * umístěný na zadané pozici.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     */
    public Semafor(int x, int y)
    {
        this(x, y, IMPLICITNÍ_BARVA_KRABICE);
    }


    /***************************************************************************
     * Vytvoří semafor implicitních rozměrů s krabicí zadané barvy
     * umístěný na zadané pozici.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param barvaKrabice  Požadovaná barva krabice se světly
     */
    public Semafor(int x, int y, Barva barvaKrabice)
    {
        this(x, y, IMPLICITNÍ_MODUL, barvaKrabice);
    }


    /***************************************************************************
     * Vytvoří semafor zadaných rozměrů s krabicí implicitní barvy
     * umístěný na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
//%I+ <136
//     * @param modul Šířka semaforu a průměr jeho světel
//%I-
//%A+ >136
     * @param modul Strana čtvercovéhzo políčka, v němž bude semafor umístěn,
     *              šířka semaforu a průměr jeho světel je 1/4 této velikosti
//%A-
     */
    public Semafor(int x, int y, int modul)
    {
        this(x, y, modul, IMPLICITNÍ_BARVA_KRABICE);
    }

//%A+ >136

    /***************************************************************************
     * Vytvoří semafor zadaných rozměrů s krabicí implicitní barvy
     * umístěný na zadaných souřadnicích a natočený do zadaného směru.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param modul Strana čtvercovéhzo políčka, v němž bude semafor umístěn,
     *              šířka semaforu a průměr jeho světel je 1/4 této velikosti
     * @param směr  Směr, do nějž bude vytvořený semafor natočen
     */
    public Semafor(int x, int y, int modul, Směr8 směr)
    {
        this(x, y, modul, IMPLICITNÍ_BARVA_KRABICE, směr);
    }

//%A-

    /***************************************************************************
     * Vytvoří semafor zadaných rozměrů s krabicí zadané barvy
     * umístěný na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
//%I+ <136
//     * @param modul Šířka semaforu a průměr jeho světel
//%I-
//%A+ >136
     * @param modul Strana čtvercovéhzo políčka, v němž bude semafor umístěn,
     *              šířka semaforu a průměr jeho světel je 1/4 této velikosti
//%A-
     * @param barvaKrabice  Požadovaná barva krabice se světly
     */
    public Semafor(int x, int y, int modul, Barva barvaKrabice)
    {
//%I+ <136
//        počet   = počet + 1;
//        this.ID = počet;
//
//        krabice = new Obdélník(x, y,  modul, 3*modul, barvaKrabice);
//
//        červená = new Světlo  (x, y,         modul, Barva.ČERVENÁ, Barva.ŽÁDNÁ);
//        žlutá   = new Světlo  (x, y+  modul, modul, Barva.ŽLUTÁ,   Barva.ŽÁDNÁ);
//        zelená  = new Světlo  (x, y+2*modul, modul, Barva.ZELENÁ,  Barva.ŽÁDNÁ);
//    }
//%I-
//%A+ >136
        this(x, y, modul, IMPLICITNÍ_BARVA_KRABICE, IMPLICITNÍ_SMĚR);
    }


    /***************************************************************************
     * Vytvoří semafor zadaných rozměrů s krabicí zadané barvy
     * umístěný na zadaných souřadnicích a otočený zadaným směrem.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param modul Strana čtvercovéhzo políčka, v němž bude semafor umístěn,
     *              šířka semaforu a průměr jeho světel je 1/4 této velikosti
     * @param barvaKrabice  Požadovaná barva krabice se světly
     * @param směr  Směr, do nějž bude vytvořený semafor natočen
     */
    public Semafor(int x, int y, int modul, Barva barvaKrabice, Směr8 směr)
    {
        počet   = počet + 1;
        this.ID = počet;

        this.xPos  = x;
        this.yPos  = y;
        this.modul = modul;
        this.směr  = směr;

        int m1 = modul;
        int m2 = modul / 2;
        int m4 = modul / 4;
        int m34= 3 * modul / 4;

        Oblast ref = new Oblast(x, y, modul, modul);
        Oblast díl;

        //krabice
        díl = new Oblast(m4, 0, m34, m4);
        díl = směr.otočVOblast(díl, ref);
        this.krabice = new Obdélník(díl, barvaKrabice);

        //červená
        díl = new Oblast(m34, 0, m4, m4);
        díl = směr.otočVOblast(díl, ref);
        this.červená = new Světlo(díl.x, díl.y, díl.výška,
                                  Barva.ČERVENÁ, Barva.ŽÁDNÁ);

        //žlutá
        díl = new Oblast(m2, 0, m4, m4);
        díl = směr.otočVOblast(díl, ref);
        this.žlutá = new Světlo(díl.x, díl.y, díl.výška,
                                Barva.ŽLUTÁ, Barva.ŽÁDNÁ);

        //zelená
        díl = new Oblast(m4, 0, m4, m4);
        díl = směr.otočVOblast(díl, ref);
        this.zelená = new Světlo(díl.x, díl.y, díl.výška,
                                 Barva.ZELENÁ, Barva.ŽÁDNÁ);
//%A-
//%A+ >142
        
        //Budeme začínat se zhasnutým semaforem
        zhasni();
//%A-
//%A+ >136
    }
//%A-
    


//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    // Sada přístupových metod vlastnosti: Pozice ******************************

    /***************************************************************************
     * Vrátí x-ovou (vodorovnou) souřadnici pozice instance.
     *
     * @return  x-ová souřadnice.
     */
    public int getX()
    {
//%I+ <136
//        return krabice.getX();
//%I-
//%A+ >136
        return xPos;
//%A-
    }


    /***************************************************************************
     * Vrátí y-ovou (svislou) souřadnici pozice instance.
     *
     * @return  y-ová souřadnice.
     */
    public int getY()
    {
//%I+ <136
//        return krabice.getY();
//%I-
//%A+ >136
        return yPos;
//%A-
    }


    /***************************************************************************
     * Vrátí přepravku se svojí aktuální pozicí.
     *
     * @return Aktuální pozice světla
     */
    @Override
    public Pozice getPozice()
    {
        return new Pozice(getX(), getY());
    }


    /***************************************************************************
     * Nastaví novou pozici světla.
     *
     * @param p Nastavovaná pozice
     */
    @Override
    public void setPozice(Pozice p)
    {
        this.setPozice(p.x, p.y);
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozice instance
     * @param y   Nová y-ová pozice instance
     */
    @Override
    public void setPozice(int x, int y)
    {
//%I+ <136
//        int modul = krabice.getŠířka();
//
//        krabice.setPozice(x, y);
//        červená.setPozice(x, y);
//        žlutá  .setPozice(x, y + modul);
//        zelená .setPozice(x, y + 2*modul);
//%I-
//%A+ >136
        int dx = x - getX();
        int dy = y - getY();
        SP.nekresli(); {
            krabice.posunVpravo(dx);       krabice.posunDolů  (dy);
            červená.setPozice(červená.getX()+dx, červená.getY()+dy);
            žlutá  .setPozice(žlutá  .getX()+dx, žlutá  .getY()+dy);
            zelená .setPozice(zelená .getX()+dx, zelená .getY()+dy);
        } SP.vraťKresli();
        xPos = x;
        yPos = y;
//%A-
    }


    // Sada přístupových metod vlastnosti: Rozměr / Modul **********************

    /***************************************************************************
     * Vrátí základní délku, od níž se odvozují všechny rozměry objektu -
     * pro semafor je to šířka krabice spolu s průměrem jeho světel.
     *
     * @return Šířka krabice spolu s průměrem světel
     */
    @Override
    public int getModul()
    {
//%I+ <136
//        return krabice.getŠířka();
//%I-
//%A+ >136
        return modul;
//%A-
    }


    /***************************************************************************
     * Nastaví nový modul představující šířku krabice a průměr světel.
     *
     * @param modul  Nově nastavovaný modul
     */
    @Override
    public void setModul(int modul)
    {
//%A+ >139
        if (modul <= 0) {
            throw new IllegalArgumentException(
                    "\nVelikost modulu musí být nezáporná - zadáno " + modul);
        }
//%A-
//%I+ <136
//        krabice.setRozměr(modul, 3*modul);
//        červená.setModul (modul);
//        žlutá  .setModul (modul);
//        zelená .setModul (modul);
//
//        int x = krabice.getX();
//        int y = krabice.getY();
//        žlutá  .setPozice(x, y + modul);
//        zelená .setPozice(x, y + 2*modul);
//        krabice.setRozměr(modul, 3*modul);
//    }
//
//%I-
//%A+ >136
        int m1 = modul;
        int m2 = modul / 2;
        int m4 = modul / 4;
        int m34= 3 * modul / 4;

        Oblast ref = new Oblast(xPos, yPos, modul, modul);
        Oblast díl;

        SP.nekresli(); {
            //krabice
            díl = new Oblast(m4, 0, m34, m4);
            díl = směr.otočVOblast(díl, ref);
            this.krabice.setOblast(díl);

            //červená
            díl = new Oblast(m34, 0, m4, m4);
            díl = směr.otočVOblast(díl, ref);
            this.červená.setPozice(díl.x, díl.y);
            this.červená.setModul(díl.výška);

            //žlutá
            díl = new Oblast(m2, 0, m4, m4);
            díl = směr.otočVOblast(díl, ref);
            this.žlutá.setPozice(díl.x, díl.y);
            this.žlutá.setModul(díl.výška);

            //zelená
            díl = new Oblast(m4, 0, m4, m4);
            díl = směr.otočVOblast(díl, ref);
            this.zelená.setPozice(díl.x, díl.y);
            this.zelená.setModul(díl.výška);
        } SP.vraťKresli();
        this.modul = modul;
    }


    /***************************************************************************
     * Vrátí směr, do nějž je šipka natočena.
     *
     * @return Směr, do nějž je šipka natočena
     */
    @Override
    public Směr8 getSměr()
    {
        return směr;
    }


    /***************************************************************************
     * Natočí šipku do zadaného směru.
     *
     * @param směr  Směr, do nějž se má šipka natočit
     */
    @Override
    public void setSměr(Směr8 směr)
    {
//%A-
//%A+ >139
        if (! směr.isHlavní()) {
            throw new IllegalArgumentException(
                "\nNebyl zadán hlavní směr - zadáno " + směr);
        }
//%A-
//%A+ >136
        this.směr = směr;
        this.setModul(modul);
    }

//%A-
//%A+ >142

    /***************************************************************************
     * Vrátí stav, v němž se semafor právě nachází;
     * stav semaforu určuje, která světla právě svítí.
     *
     * @return Aktuální stav semaforu
     */
    public StavSemaforu getStav()
    {
        return stav;
    }


    /***************************************************************************
     * Nastaví zadaný stav semaforu, tj. rozvítí světla odpovídající
     * zadanému stavu.
     *
     * @param stav Nastavovaný stav
     */
    public void setStav(StavSemaforu stav)
    {
        //Nemusím nastavovat stav - ten nastaví spuštěná metoda
//%A-
//%I+ >142 -143
//        if        (stav == NIC)   {
//            zhasni();
//        } else if (stav == POZOR) {
//            pozor();
//        } else if (stav == STŮJ)  {
//            stůj();
//        } else if (stav == PŘIPRAVIT) {
//            připravit();
//        } else if (stav == VOLNO) {
//            volno();
//        } else if (stav == VŠE)   {
//            rozsviťVše();
//        } else {
//            throw new IllegalArgumentException(
//                "\nZadán neznámý stav semaforu: " + stav);
//        }
//%I-
//%A+ >143
        switch (stav)
        {
            case NIC:       zhasni();       return;
            case POZOR:     pozor();        return;
            case STŮJ:      stůj();         return;
            case PŘIPRAVIT: připravit();    return;
            case VOLNO:     volno();        return;
            case VŠE:       rozsviťVše();   return;

            default:
                throw new IllegalArgumentException(
                    "\nZadán neznámý stav semaforu: " + stav);
        }
//%A-
//%A+ >142
    }

//%A-


//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Projde se semaforem postupně všemi fázemi standardního cyklu, přičemž
     * počet milisekund, po něž semafor setrvá v každé fázi je dán velikostí
     * příslušného parametru.
     *
     * @param stůj      Doba, po níž bude svítit pouze červená
     * @param připravit Doba, po níž bude svítit červená se žlutou
     * @param volno     Doba, po níž bude svítit pouze zelená
     * @param pozor     Doba, po níž bude svítit pouze žlutá
     * @param nic       Doba, po níž budou všechny světla zhasnutá
     */
    public void cyklus(int stůj, int připravit, int volno, int pozor, int nic)
    {
        stůj();         IO.čekej(stůj);
        připravit();    IO.čekej(připravit);
        volno();        IO.čekej(volno);
        pozor();        IO.čekej(pozor);
        zhasni();       IO.čekej(nic);
    }


    /***************************************************************************
     * Projde se semaforem postupně všemi fázemi standardního cyklu, přičemž
     * se v každé fázi "zdrží" půl vteřiny.
     */
    public void cyklus()
    {
        cyklus(500, 500, 500, 500, 500);
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param kreslítko Kreslítko, které nakreslí instanci
     */
    @Override
    public void nakresli(Kreslítko kreslítko)
    {
        krabice.nakresli(kreslítko);
        červená.nakresli(kreslítko);
        žlutá  .nakresli(kreslítko);
        zelená .nakresli(kreslítko);
    }


    /***************************************************************************
     * Rozsvítí na semaforu žlutou a zhasne ostatní světla.
     */
    public void pozor()
    {
        červená.zhasni();
        žlutá  .rozsviť();
        zelená .zhasni();
//%A+ >142
        stav = POZOR;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na semaforu červenou a oranžovou a zhasne zelenou.
     */
    public void připravit()
    {
        červená.rozsviť();
        žlutá  .rozsviť();
        zelená .zhasni();
//%A+ >142
        stav = PŘIPRAVIT;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na semaforu červenou a zhasne ostatní světla.
     */
    public void stůj()
    {
        červená.rozsviť();
        žlutá  .zhasni();
        zelená .zhasni();
//%A+ >142
        stav = STŮJ;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na semaforu zelenou a zhasne ostatní světla.
     */
    public void volno()
    {
        červená.zhasni();
        žlutá  .zhasni();
        zelená .rozsviť();
//%A+ >142
        stav = VOLNO;
//%A-
    }


    /***************************************************************************
     * Zhasne všechna světla semaforu.
     */
    public void zhasni()
    {
        červená.zhasni();
        žlutá  .zhasni();
        zelená .zhasni();
//%A+ >142
        stav = NIC;
//%A-
    }

//%A+ >142

    /***************************************************************************
     * Zhasne všechna světla semaforu.
     */
    public void rozsviťVše()
    {
        červená.rozsviť();
        žlutá  .rozsviť();
        zelená .rozsviť();
        stav = VŠE;
    }

//%A-

    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "Semafor_" + ID + "(" + getPozice() + ", modul=" + getModul() +
               ", krabice=" + krabice.getBarva() + ")";
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        Světlo inst = new Světlo();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}

//%%-  ----- Začátek ignorovaného závěrečného textu -----
////////////////////////////////////////////////////////////////////////////////
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        new Semafor();
//        new Semafor(100, 100);
//        new Semafor(200,  50, Barva.HNĚDÁ);
////        System.exit(0);
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}
